package com.pc.tas.web;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;


import com.pc.cloud.services.*;
import com.pc.cloud.utils.NamePair;
import com.pc.tas.export.ExportResult;
import com.pc.tas.export.expfilelist.ExpFileList;
import com.pc.tas.learning.trace.index.TraceSearchArgs;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TraceAnaylyzeController {
	final public static MathContext mctx = new MathContext(20);
	final public static BigDecimal hundrend = new BigDecimal(100);
	
	@Autowired
	private SearchServices searchServices;

	@RequestMapping("/trace/analyze")
	@ResponseBody
	public String analyze(@RequestParam Map<String,String> params) {
		try{					
			TraceSearchArgs tsa = new TraceSearchArgs();
			String dimension = null;
			String viewType = null;
			String sort = null;
			Map<String,String> args = new HashMap<String,String>();
			Map<String,String[]> ranges = new HashMap<String,String[]>();
			Map<String,List<MetricArg>> fields = new HashMap<String,List<MetricArg>>();
			int offset = 0;
			int limit = 15;
			for(Entry<String,String> entry : params.entrySet()) {
//String key = entry.getKey().replace("-", ".");
				String key = entry.getKey();
				String value = entry.getValue();
				//if(key.startsWith("filter_") && !"filter_category".equals(key)) {		//filter_category do not to filter for the present.	
				if(key.startsWith("filter_")) {
					if(value!=null && !"null".equals(value)) {
						args.put(key.substring(7), value);
					}					
				} else if(key.startsWith("range_begin_")) {
					String v = value;
					if(v != null && !"null".equals(v)) {
						String k = key.substring(12);
						String[] rs = ranges.get(k);
						if(rs != null) {
							rs[0] = v; 
						} else {
							rs = new String[2];
							rs[0] = v;
							ranges.put(k, rs);
						}
					}					
				} else if(key.startsWith("range_end_")) {
					String v = value;
					if(v != null && !"null".equals(v)) {
						String k = key.substring(10);
						String[] rs = ranges.get(k);
						if(rs != null) {
							rs[1] = v; 
						} else {
							rs = new String[2];
							rs[1] = v;
							ranges.put(k, rs);
						}
					}		
				} else if(key.startsWith("dimension_")) {
					dimension = key.substring(10);
				} else if(key.startsWith("metric_sum_")){
					String subkey = key.substring(11);
					String[] keys = subkey.split("_");
					if(keys.length > 1){
						viewType = keys[0];
					}
					//String[] types = keys[keys.length-1].split("\\^");
					String[] types = subkey.split("\\^");
					List<MetricArg> metricArgs = fields.get(types[0]);
					if(metricArgs == null || metricArgs.size() == 0){
						metricArgs = new ArrayList<MetricArg>();
						metricArgs.add(new MetricArg(types[1], MetricArg.SUM));
						fields.put(types[0], metricArgs);
					}else{
						fields.get(types[0]).add(new MetricArg(types[1], MetricArg.SUM));
					}
				}else if(key.startsWith("metric_count_")) {
					String subkey = key.substring(13);
					String[] keys = subkey.split("_");
					if(keys.length > 1){
						viewType = keys[0];
					}
					//String[] types = keys[keys.length-1].split("\\^");
					String[] types = subkey.split("\\^");
					List<MetricArg> metricArgs = fields.get(types[0]);
					if(metricArgs == null || metricArgs.size() == 0){
						metricArgs = new ArrayList<MetricArg>();
						metricArgs.add(new MetricArg(types[1], MetricArg.COUNT));
						fields.put(types[0], metricArgs);
					}else{
						fields.get(types[0]).add(new MetricArg(types[1], MetricArg.COUNT));
					}
				} else if(key.startsWith("metric_distinct_count_")) {
					String subkey = key.substring(22);
					String[] keys = subkey.split("_");
					if(keys.length > 1){
						viewType = keys[0];
					}
					//String[] types = keys[keys.length-1].split("\\^");
					String[] types = subkey.split("\\^");
					List<MetricArg> metricArgs = fields.get(types[0]);
					if(metricArgs == null || metricArgs.size() == 0){
						metricArgs = new ArrayList<MetricArg>();
						metricArgs.add(new MetricArg(types[1], MetricArg.DISTINCT_COUNT));
						fields.put(types[0], metricArgs);
					}else{
						fields.get(types[0]).add(new MetricArg(types[1], MetricArg.DISTINCT_COUNT));
					}
				} else if(key.startsWith("metric_orderChangeRate")) {
					
				}else if(key.equals("offset")){
					offset = Integer.parseInt(value);
				}else if(key.equals("limit")){
					limit = Integer.parseInt(value);
				}else if("sort".equals(key)){
					String[] sortFields = value.split("\\^");
					sort = sortFields[1];
				}
			}
			
			if(args.size() > 0) {
				tsa.setOtherParams(args);
			}

			if(ranges.size() > 0) {
				tsa.setOtherRange(ranges);
			}
			Map<String,SearchResults> results = new HashMap<String,SearchResults>();
			
			for(Entry<String,List<MetricArg>> entry : fields.entrySet()){
				String type = entry.getKey();
				List<MetricArg> metricFields = entry.getValue();
				if(dimension != null && !"".equals(dimension)) {
					FacetQueryArg fs = new FacetQueryArg();
					fs.setFacetField(dimension);
					fs.setMetricFields(metricFields);
					fs.setOffset(offset);//分页 ，第几页
					fs.setLimit(limit);//分页  。每页多少条记录
					if(sort != null){
						fs.setSort(sort);//排序指标
					}
					tsa.setType(type);
					tsa.getFacetQueryFields().add(fs);
				} else {
					tsa.setType(type);
					tsa.setMetricFields(metricFields);
				}	
				SearchResults res = searchServices.search(tsa);
				System.out.println(res.getTotal());
				results.put(type, res);
			}
			
			JSONArray jitems = new JSONArray();
			int total = 0;
			if(dimension != null && !"".equals(dimension)) {
				total = this.getSumFacetJSON(results,jitems);
			}else{
				this.getSumJSON(results,jitems);		
				total = 1;
			}
			
			JSONObject result = new JSONObject();
			result.put("records", jitems);
			result.put("total", total);
			return result.toString();
		}catch(Throwable e){
			e.printStackTrace();
			return "error:" + e.getMessage();
		}
	}

	private void getSumJSON(Map<String,SearchResults> results, JSONArray jitems) throws Exception {
		JSONObject jo = new JSONObject();
		jo.put("name", "总计");
		for(String type : results.keySet()){
			SearchResults sr = results.get(type);
			Collection<NamePair> sums = sr.getSum();
			if(sums != null && sums.size()>0) {
				for(NamePair np : sums) {
					System.out.println(np.getName() + " : " + np.getValue());
					String name = "metric_" + type + "^" + np.getName();
					jo.put(name, np.getValue());
				}
				//to get exitRate   
				try{
					long pv = jo.getLong("metric_view^pv");
					long exit = jo.getLong("metric_view^exit");
                    String rate = getExitRate(exit,pv);
                    jo.put("metric_view^exitRate",rate);
				}catch(Exception e){
					//e.printStackTrace();
				}
			}
		}		
		jitems.put(jo);	
	}
	
	private int getSumFacetJSON(Map<String,SearchResults> results, JSONArray jitems) throws Exception {
		int total = 0;
		for(String type : results.keySet()){
			SearchResults sr = results.get(type);
			Map<String,Collection<FacetSearchRow>> sumFacets = sr.getSumFacets();
			if(sumFacets != null && sumFacets.size() > 0) {
				for(Entry<String,Collection<FacetSearchRow>> entry : sumFacets.entrySet()) {
					Collection<FacetSearchRow> fsrs = entry.getValue();
					for(FacetSearchRow fsr : fsrs){
						total = fsr.getTotal();
						JSONObject jo = new JSONObject();
						String[] names = fsr.getName().split("\\^\\~");
						if(names.length == 0)continue;
						jo.put("name", names[0]);
						if(names.length == 2){
							jo.put("url", names[1]);
						}
						Collection<NamePair> nps = fsr.getPairs();
						for(NamePair np : nps) {
							String name = "metric_" + type + "^" + np.getName();
							jo.put(name, np.getValue());	
							
						}
						//to get exitRate   
						try{
							long pv = jo.getLong("metric_view^pv");
							long exit = jo.getLong("metric_view^exit");
		                    String rate = getExitRate(exit,pv);
		                    jo.put("metric_view^exitRate",rate);
						}catch(Exception e){
							//e.printStackTrace();
						}
						jitems.put(jo);
					}
				}
			}
		}
		return total;
	}
	
    private String getExitRate(long exits, long pv) {
        if (pv != 0) {
        	BigDecimal rate = new BigDecimal(exits).divide(new BigDecimal(pv), mctx).multiply(hundrend).setScale(2,BigDecimal.ROUND_HALF_UP);
            return rate + "%";
        }
        return "0%";
    }
	@Autowired
	private ExportResult export;
	
	@RequestMapping("/trace/export")
	@ResponseBody
	public String export(@RequestParam Map<String,String> params,HttpServletRequest request){
		String fileName = params.get("fileName");
		String column = params.get("column");
		String[] columns = column.split(",");
		
		try{
			JSONArray fields = new JSONArray();
			for(String field : columns){
				JSONObject jo = new JSONObject();
				String[] item = field.split(":");
				jo.put(item[0], item[1]);
				fields.put(jo);
			}
			export.setExpType(ExpFileList.EXP_TYPE_TRACE);
			export.createFile(request, fileName, fields);
			
			int offset = 0;
			while(true){
				params.put("offset", String.valueOf(offset));
				params.put("limit", String.valueOf(1000));
				String result = this.analyze(params);
				
				JSONObject res = new JSONObject(result);
				JSONArray jarr = res.getJSONArray("records");
				if(jarr.length() <= 0 )break;
				export.doExport(jarr);
				boolean flag = false;
				for(Entry<String,String> entry : params.entrySet()) {
					String key = entry.getKey();
					if(key.startsWith("dimension_")){
						flag = true;
					}
				}
				if(!flag)break;
				offset = offset + 1000;
			}
			export.close();
			if(!export.isHasData())return "0";
			return "1";
		}catch(Exception e){
			e.printStackTrace();
		}
		return "-1";
	}
	
	
	@RequestMapping("/trace/loginAnalyze")
	@ResponseBody
	public String loginAnalyze(@RequestParam String beginDate,@RequestParam String endDate) {
		try{					
			TraceSearchArgs tsa = new TraceSearchArgs();					
			String viewType = null;
			Map<String,String[]> ranges = new HashMap<String,String[]>();
			JSONArray jitems = new JSONArray();
			int offset = 0;
			int limit = 1000;
			
			String[] times = new String[2];
			times[0] = beginDate;
			times[1] = endDate;
			ranges.put("time", times);
			
			if(ranges.size() > 0) {
				tsa.setOtherRange(ranges);
			}
			String dimension = "user-id";
			while(true){
				Map<String,SearchResults> results = new HashMap<String,SearchResults>();
				List<MetricArg> metricFields = new ArrayList<MetricArg>();
				metricFields.add(new MetricArg(dimension, MetricArg.DISTINCT_COUNT));
				
				FacetQueryArg fs = new FacetQueryArg();
				fs.setFacetField(dimension);
				fs.setMetricFields(metricFields);
				fs.setOffset(offset);//分页 ，第几页
				fs.setLimit(limit);//分页  。每页多少条记录
				tsa.setType("view");
			//	tsa.setViewType(viewType);
				tsa.getFacetQueryFields().add(fs);
			
				SearchResults res = searchServices.search(tsa);
				Map<String,Collection<FacetSearchRow>> sumFacets = res.getSumFacets();
				Collection<FacetSearchRow> rows = sumFacets.get(dimension);
				if(rows.size() <= 0){
					break;
				}
				results.put("view", res);
				int total = this.getSumFacetJSON(results,jitems);
				offset = offset + 1000;
				
			}
			JSONArray users = new JSONArray();
			for(int i = 0; i < jitems.length(); i ++){
				JSONObject jo = (JSONObject)jitems.get(i);
				users.put(jo.optString("name"));
			}
			return users.toString();
		}catch(Throwable e){
			e.printStackTrace();
			return "error:" + e.getMessage();
		}
	}

}
